package com.umpay.util;

import com.umpay.dict.DataDict;
import com.umpay.dict.SysConst;
import com.umpay.dict.retcode.MerAccessEC;
import com.umpay.exception.BusinessException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.crypto.Cipher;
import java.io.InputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;

/**
 * *********************************************************************** <br>
 * description : 用公司公钥进行RSA解密
 * 
 * @author xiatian
 * @date May 7, 2013 3:13:15 PM
 * @version 1.0
 */
public class DecryptRsaUtil {

    private static final Logger log = LogManager.getLogger(DecryptRsaUtil.class);
    private static PrivateKey pk;
    private static Boolean initPk = false;

    /**
     * <br>
     * description : 加载证书文件
     * 
     * @author xiatian
     * @version 1.0
     * @date May 7, 20133:10:44 PM
     */
    private static void loadPlatPublicKey() {
        if (!initPk) {
            synchronized (initPk) {
                if (!initPk) {
                    String platPkPath = PropertiesUtil.getStrValue("plat_key");
                    InputStream in = null;
                    try {
                        byte[] b = new byte[4096];
                        in = DecryptRsaUtil.class.getClassLoader().getResourceAsStream(platPkPath);
                        in.read(b);
                        PKCS8EncodedKeySpec peks = new PKCS8EncodedKeySpec(b);
                        KeyFactory kf = KeyFactory.getInstance("RSA");
                        pk = kf.generatePrivate(peks);
                        initPk = true;
                    } catch (Exception ex) {
                        log.info("----------in=", ex);
                        RuntimeException exc = new RuntimeException(ex.getMessage());
                        exc.setStackTrace(ex.getStackTrace());
                        throw exc;
                    } finally {
                        try {
                            if (null != in)
                                in.close();
                        } catch (Exception ex) {
                            ;
                        }
                    }
                }
            }
        }
    }

    /**
     * <br>
     * description : 用私钥解密
     * 
     * @param req
     * @return
     * @throws Exception
     * @author zhangru
     * @version 1.0
     * @date 20160112
     */
    public static String reqParamDecryptByPK(String key, String data) {
        try {
            loadPlatPublicKey();
            log.debug(String.format("密文：%s", data));
            byte[] b = Base64Util.decode(data.getBytes("UTF-8"));
            byte[] retB = decryptByPrivateKey(b);
            String retData = new String(retB);
            if (retData.length() > 10) {
                log.debug("解密后：" + StringProcessor.processIdToStar(retData));
            }
            return retData;
        } catch (Exception e) {
            log.error(String.format("RSA解密%s失败", key), e);
            throw new BusinessException(SysConst.INVALIDPARAM, String.format("请求的参数[%s]格式或值不正确", key));
        }
    }

    /**
     * <br>
     * description : 用私钥解密
     * 
     * @param req
     * @return
     * @throws Exception
     * @author xiatian
     * @version 1.0
     * @date May 7, 20133:18:55 PM
     */
    public static String decryptByPK(String data) throws Exception {
        loadPlatPublicKey();
        log.debug(String.format("密文：%s", data));
        byte[] b = Base64Util.decode(data.getBytes("UTF-8"));
        byte[] retB = decryptByPrivateKey(b);
        String retData = new String(retB, "UTF-8");
        if (retData.length() > 10) {
            log.debug("解密后：" + StringProcessor.processIdToStar(retData));
        }
        return retData;
    }

    /**
     * 使用联动私钥解密
     * 
     * @param data
     *            密文
     * @param encodeType
     *            密文的编码方式
     * @return
     * @throws Exception
     * @throws Exception
     */
    public static String decryptByPK(String data, String encodeType) throws Exception {
        loadPlatPublicKey();
        log.debug(String.format("密文：%s", data));
        byte[] b;
        if (DataDict.ENCODE_HEX.equals(encodeType)) {
            b = org.bouncycastle.util.encoders.Hex.decode(data);
        } else if (DataDict.ENCODE_BASE64.equals(encodeType)) {
            b = Base64Util.decode(data.getBytes("UTF-8"));
        } else {
            b = Base64Util.decode(data.getBytes("UTF-8"));// 默认使用Base64解码
        }
        try {
            byte[] retB = decryptByPrivateKey(b);
            String retData = new String(retB);
            if (retData.length() > 10) {
                log.debug("解密后：" + StringProcessor.processIdToStar(retData));
            }
            return retData;
        } catch (Exception e) {
            log.error("【解密】使用联动私钥解密失败");
            throw new BusinessException(MerAccessEC.EN_DE_CRYPTION_ERROR, "解密支付要素失败");
        }
    }

    /**
     * 使用联动私钥解密
     * 
     * @param data
     *            密文
     * @param encodeType
     *            密文的编码方式
     * @return
     * @throws Exception
     * @throws Exception
     */
    public static String decryptByPKUtf8(String data, String encodeType) throws Exception {
        loadPlatPublicKey();
        log.debug(String.format("密文：%s", data));
        byte[] b;
        if (DataDict.ENCODE_HEX.equals(encodeType)) {
            b = org.bouncycastle.util.encoders.Hex.decode(data);
        } else if (DataDict.ENCODE_BASE64.equals(encodeType)) {
            b = Base64Util.decode(data.getBytes("UTF-8"));
        } else {
            b = Base64Util.decode(data.getBytes("UTF-8"));// 默认使用Base64解码
        }
        try {
            byte[] retB = decryptByPrivateKey(b);
            String retData = new String(retB, "UTF-8");
            if (retData.length() > 10) {
                log.debug("解密后：" + StringProcessor.processIdToStar(retData));
            }
            return retData;
        } catch (Exception e) {
            log.error("【解密】使用联动私钥解密失败");
            throw new BusinessException(MerAccessEC.EN_DE_CRYPTION_ERROR, "解密支付要素失败");
        }
    }

    /**
     * <br>
     * description : 用私钥进行解密
     * 
     * @param data
     * @return
     * @throws Exception
     * @author xiatian
     * @version 1.0
     * @date May 7, 20133:12:35 PM
     */
    private static byte[] decryptByPrivateKey(byte[] data) throws Exception {
        // 对密钥解密
        byte[] keyBytes = pk.getEncoded();
        log.debug(new String(Base64Util.encode(keyBytes)));
        // 取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        // 对数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }
    public static void main (String args[]) throws Exception {
		String data = "TKNX0Ancbr6NNcCo4BSc+JNhelEWMj1TnjJDl862gtXbWOOM0aUDw/ds9TfUMLssSK7CfJdjvsB6wloAeLGNZ4/PWTqLhbRWVCcFRTrNfDPHkFO4IXSINeVCif7dAIuqRZh8YuYJzyPMb4w8pgmbqjhcKRzotK/vpZtF+GdcA04=";
	    System.out.println("*******"+decryptByPK(data));
    }
    
}
